//Blackjack
//Plays a simple version of the casino game of blackjack; for 1 - 7 players

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <sstream>

#include "b.h"

class QLabel;
class QString;


using namespace std;


Card::Card(Rank r, Suit s, bool isFace):  rank(r), suit(s), isFaceUp(isFace)
{
	//cout << "Card::Card() constructor" << endl;
} 

int Card::getValue() const
{
    //if a cards is face down, its value is 0
    int value = 0;
    if (isFaceUp)
    {
        //value is number showing on card
        value = rank;
        //value is 10 for face cards
        if (value > 10)
            value = 10;
    }
    return value;
}

void Card::flip()
{
    isFaceUp = !(isFaceUp);
}


Hand::Hand()
{
	cout << "Hand::Hand() constructor" << endl;
    cards.reserve(7);
}

Hand::~Hand()  
{
    clear();
    cout << "destructor Hand" << endl;
}

void Hand::add(Card* pCard)
{
    cards.push_back(pCard);
}
 
void Hand::clear()
{
    //iterate through vector, freeing all memory on the heap
    vector<Card*>::iterator iter = cards.begin();
    for (iter = cards.begin(); iter != cards.end(); ++iter)
    {
        delete *iter;
        *iter = 0;
    }
    //clear vector of pointers
    cards.clear();
}

int Hand::getTotal() const
{
    //if no cards in hand, return 0
    if ( cards.empty())
        return 0;
  
    //if a first card has value of 0, then card is face down; return 0
    if (cards[0]->getValue() == 0)
        return 0;
    
    //add up card values, treat each Ace as 1
    int total = 0;
    vector<Card*>::const_iterator iter;
    for (iter = cards.begin(); iter != cards.end(); ++iter)
        total += (*iter)->getValue();
                  
    //determine if hand contains an Ace
    bool containsAce = false;
    for (iter = cards.begin(); iter != cards.end(); ++iter)
        if ((*iter)->getValue() == Card::ACE)
            containsAce = true;
          
    //if hand contains Ace and total is low enough, treat Ace as 11
    if (containsAce && total <= 11)
        //add only 10 since we've already added 1 for the Ace
        total += 10;   
            
    return total;
}

AbstractPlayer::AbstractPlayer(const string& s): name(s)
{
	cout << "AbstractPlayer::AbstractPlayer() constructor ->Hand" << endl;
}

AbstractPlayer::~AbstractPlayer()  
{
    	cout << "destructor AbstractPlayer" << endl;
}

string AbstractPlayer::getName() const
{ 
    return name;
}

QString& AbstractPlayer::getLabelQStr() const
{ 
    return labelQStr;
}

bool AbstractPlayer::isBusted() const
{ 
    return (getTotal() > 21);
}

void AbstractPlayer::bust() const
{
    string str = "";
    ostringstream oss ;
    oss << "";
    cout << name << " busts.\n";
    oss << name << " bust! ";
    str = oss.str();
    cout << "str =" << str << endl;
    labelQStr = str.c_str();
   // canvas->setStateLabel(qstr);
}

Player::Player(bool b, const string& name):  AbstractPlayer(name)
{
	cout << "Player::Player() constructor ->AbstractPlayer" << endl;
}

Player::~Player()
{
    	cout << "destructor Player" << endl;
}
    
bool Player::isHitting() const
{
/*
    cout << name << ", do you want a hit? (Y/N): ";
    char response;
    cin >> response;
    return (response == 'y' || response == 'Y');
*/
    while(!hitPressed) {}
    return true;
}

void Player::win() const
{
    cout << name <<  " wins.\n";
}

void Player::lose() const
{
    cout << name <<  " loses.\n";
}

void Player::push() const
{
    cout << name <<  " pushes.\n";
}

void Player::setHitPressed()
{
    hitPressed = true;
}

House::House(const string& name): 
    AbstractPlayer(name)
{
	cout << "House::House() constructor ->AbstractPlayer " << endl;
}

House::~House()
{
	cout << "destructor House" << endl;
}

bool House::isHitting() const
{
    return (getTotal() <= 16);
}   

void House::flipFirstCard()
{
    if (!(cards.empty()))
        cards[0]->flip();
    else cout << "No card to flip!\n";
}

Deck::Deck()
{ 
    cout << "Deck::Deck() constructor ->Hand" << endl;
    cards.reserve(52);
    populate();
}

Deck::~Deck()
{ 
	cout << "destructor Deck" << endl;
}

void Deck::populate()
{
    clear();
    //create standard deck
    for (int s = Card::CLUBS; s <= Card::SPADES; ++s)
            for (int r = Card::ACE; r <= Card::KING; ++r)
                add(new Card(static_cast<Card::Rank>(r), static_cast<Card::Suit>(s)));
}

void Deck::shuffle()
{
    random_shuffle(cards.begin(), cards.end());
}

void Deck::deal(Hand& aHand)
{
	// cards : inherited from Hand class
    cout << " Deck::deal()" << endl;
    //cout << "cards =" << cards << endl;
    if (!cards.empty())
    {
        aHand.add(cards.back());
        cards.pop_back();
    }
    else
    {
        cout << "Out of cards. Unable to deal.";
    }
}

void Deck::additionalCards(AbstractPlayer& aAbstractPlayer)
{
    cout << " Deck::additionalCards(AbstractPlayer& aAbstractPlayer) " << endl;
    //continue to deal a card as long as generic player isn't busted and
    //wants another hit
        deal(aAbstractPlayer);
        cout << " Deck::deal() done! " << endl;
        cout << aAbstractPlayer << endl;
        
    /*
        if (aAbstractPlayer.isBusted()) {
            aAbstractPlayer.bust();
    	}
    */
    /*
    while ( !(aAbstractPlayer.isBusted()) && aAbstractPlayer.isHitting() )
    {
        deal(aAbstractPlayer);
        cout << aAbstractPlayer << endl;
        
        if (aAbstractPlayer.isBusted())
            aAbstractPlayer.bust();
    }
    */
} 

Game::Game(const vector<string>& names, Canvas *cnv):canvas(cnv)
{
    cout << "Game::Game() constructor" << endl;
    //create a vector of players from a vector of names       
    vector<string>::const_iterator pName;
    for (pName = names.begin(); pName != names.end(); ++pName)      
        player.push_back(Player(false, *pName));

    srand(time(0));    //seed the random number generator
    cout << "deck.populate()" << endl;
    deck.populate();
    cout << "deck.shuffle()" << endl;
    deck.shuffle();
    cout << "Game::Game() constructor Done!" << endl;
}

Game::~Game()
{ 
	cout << "destructor Game" << endl;
}

void Game::setupTable()
{         
    //deal initial 2 cards to everyone
    vector<Player>::iterator iterPlayer;
    for (int i = 0; i < 2; ++i)
    {
        for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer)      
            deck.deal(*iterPlayer);
        deck.deal(house);
    }
        cout << "setupTable() this =" << this << endl;
        cout << "setupTable() player.size()=" << player.size() << endl;
    
    //hide house's first card
    house.flipFirstCard();    
    
    //display everyone's hand
    int jj = 0;
    for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer) {      
        cout << *iterPlayer << endl;
        cout << " jj = " << jj++ << endl;
        canvas->setPlayerStateLabel((*iterPlayer).getLabelQStr());
    }
    cout << house << endl;
    canvas->setHostStateLabel(house.getLabelQStr());
}

void Game::hitSelected()
{         
        cout << "Game::hitSelected()" << endl;
	vector<Player>::iterator iterPlayer;
        //deal additional cards to players
        cout << "hitSelected() this =" << this << endl;
        cout << "hitSelected() player.size()=" << player.size() << endl;
        for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer) {
                deck.additionalCards(*iterPlayer);
                canvas->setPlayerStateLabel((*iterPlayer).getLabelQStr());
        }
        for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer) {
        	if ((*iterPlayer).isBusted()) {
            		(*iterPlayer).bust();
            		canvas->setResultLabel((*iterPlayer).getLabelQStr());
		}
    	}
}

void Game::PlayB()
{         
    vector<Player>::iterator iterPlayer;
    //deal additional cards to players
    for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer)
        deck.additionalCards(*iterPlayer);    

    //reveal house's first card
    house.flipFirstCard();    
    cout << endl << house; 
  
    //deal additional cards to house
    deck.additionalCards(house);

    if (house.isBusted())
    {
        //everyone still playing wins
        for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer)      
            if ( !(iterPlayer->isBusted()) )
                iterPlayer->win();
    }
    else
    {
         //compare each player still playing to house
        for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer)      
            if ( !(iterPlayer->isBusted()) )
            {
                if (iterPlayer->getTotal() > house.getTotal())
                    iterPlayer->win();
                else if (iterPlayer->getTotal() < house.getTotal())
                    iterPlayer->lose();
                else
                    iterPlayer->push();
            }
    }

    //remove everyone's cards
    for (iterPlayer = player.begin(); iterPlayer != player.end(); ++iterPlayer)      
        iterPlayer->clear();
    house.clear();
}


//overloads << operator so Card object can be sent to cout
ostream& operator<<(ostream& os, const Card& aCard)
{
    const string RANKS[] = {"0", "A", "2", "3", "4", "5", "6", "7", "8", "9", 
                            "10", "J", "Q", "K"};
    const string SUITS[] = {"c", "d", "h", "s"};

    if (aCard.isFaceUp)
        os << RANKS[aCard.rank] << SUITS[aCard.suit];
    else
        os << "XX";

    return os;
}

//overloads << operator so a AbstractPlayer object can be sent to cout
ostream& operator<<(ostream& os, const AbstractPlayer& aAbstractPlayer)
{
    cout << " cout Abstract " << endl;
    string str = "";
    ostringstream oss ;
    oss << "";
    os << aAbstractPlayer.name << ":   ";
    oss << aAbstractPlayer.name << ":   ";
    
    vector<Card*>::const_iterator pCard;
    if (!aAbstractPlayer.cards.empty())
    {
        for (pCard = aAbstractPlayer.cards.begin(); 
             pCard != aAbstractPlayer.cards.end(); ++pCard) {
            os << *(*pCard) << "   ";
            oss << *(*pCard) << "   ";
            
        }
        if (aAbstractPlayer.getTotal() != 0) {
            cout << "(" << aAbstractPlayer.getTotal() << ")";
            oss << "(" << aAbstractPlayer.getTotal() << ")";
        }
    }
    else
    {
        os << "<empty>";
        oss << "<empty>";
    }
        
    str = oss.str();
    cout << "str =" << str << endl;
    aAbstractPlayer.labelQStr = str.c_str();
    return os;
}

void AbstractPlayer::makeString(string &s)
{
    QString qstr = s.c_str();
   // canvas->setStateLabel(qstr);
}


/*
void startGame()
{
    
    vector<string> names;
    string name = "You";
    names.push_back(name);

    //the game loop        
    Game myGame(names);
    

    char again = 'y';
    while (again != 'n' && again != 'N')
    {
        myGame.Play();
        cout << "\nDo you want to play again? (Y/N): ";
        cin >> again;
    } 
}
*/
/*

QMessageBox::information(this, tr("Add Successful"),
                 tr("\"%1\" has been added to your address book.").arg(name));
*/







